package org.vacoor.xqq.ui.comp.tree;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * 主要将 JTree Mouse 事件转换为 JTree Node 事件
 * <p/>
 *
 * @author: vacoor
 */
public abstract class TreeNodeMouseAdapter extends MouseAdapter {
    private static final Logger logger = LoggerFactory.getLogger(TreeNodeMouseAdapter.class);

    private int lastRow = -1;
    private JTree bindTree;

    public void bind(JTree tree) {
        unbind(bindTree);
        this.bindTree = tree;
        tree.addMouseListener(this);
        tree.addMouseMotionListener(this);
    }

    public void unbind(JTree tree) {
        if (tree != null) {
            tree.removeMouseListener(this);
            tree.removeMouseMotionListener(this);
        }
    }

    /**
     * 这里主要将树中鼠标移动转换为节点的鼠标进入/退出事件
     * <p/>
     * {@link #mouseEnteredOnNode(java.awt.event.MouseEvent, int, java.awt.Point)}
     * {@link #mouseExitedOnNode(java.awt.event.MouseEvent, int, java.awt.Point)}
     * {@link #mouseMovedOnNode(java.awt.event.MouseEvent, int, java.awt.Point)}
     */
    @Override
    public final void mouseMoved(MouseEvent e) {
        JTree tree = (JTree) e.getSource();
        int row = tree.getRowForLocation(e.getX(), e.getY());
        Rectangle bounds = tree.getRowBounds(row);

        Rectangle lastBounds = tree.getRowBounds(lastRow);
        if (-1 != lastRow && lastBounds != null) {    // 最后一个节点是显示的
            // 计算相对于最后一个节点的坐标
            // 这里有时会有1px误差
            Point lastPoint = new Point(
                    Math.max(e.getX() - lastBounds.x, 0),
                    Math.max(e.getY() - lastBounds.y, 0)
            );

            if (row != lastRow) {    // 从最后一个节点移动到另外一个节点或节点之外 (当前)
                mouseExitedOnNode(e, lastRow, lastPoint);

            } else { // 移动
                mouseMovedOnNode(e, lastRow, lastPoint);
            }
        }

        // 从其他地方移动到当前节点上
        if (row != lastRow && -1 != row) {
            Point p = new Point(
                    Math.max(e.getX() - bounds.x, 0),
                    Math.max(e.getY() - bounds.y, 0)
            );
            mouseEnteredOnNode(e, row, p);
        }

        lastRow = row;
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        JTree tree = (JTree) e.getSource();
        TreePath path = tree.getPathForLocation(e.getX(), e.getY());
        if (null == path) {
            return;
        }

        Object node = tree.getLastSelectedPathComponent();
        if (!(node instanceof TreeNode)) {
            return;
        }
        mouseClickedOnNode(e, (TreeNode) node);
    }

    // ------------------------------------------------------------------

    /**
     * 鼠标进入节点
     *
     * @param e     原始鼠标事件
     * @param row   进入节点row
     * @param point 相对于当前节点的鼠标坐标
     */
    public void mouseEnteredOnNode(MouseEvent e, int row, Point point) {
    }

    /**
     * 鼠标离开节点
     *
     * @param e     原始鼠标事件
     * @param row   离开节点的row
     * @param point 相对于离开节点的鼠标坐标
     */
    public void mouseExitedOnNode(MouseEvent e, int row, Point point) {
    }

    /**
     * 鼠标在节点上移动
     *
     * @param e     原始鼠标事件
     * @param row   当前节点的row
     * @param point 相对于当前节点的鼠标坐标
     */
    public void mouseMovedOnNode(MouseEvent e, int row, Point point) {
    }

    public void mouseClickedOnNode(MouseEvent e, TreeNode node) {
    }
}
